﻿using MongoDB.Driver;
using Newtonsoft.Json;
using Sustainalytics.ClientDW.Entities;
using Sustainalytics.DataLayer.ConnectionStrings;
using Sustainalytics.Entities;
using Sustainalytics.Entities.ConnectionStrings;
using Sustainalytics.Entities.RiskRatings;
using Sustainalytics.LongRunningTaskManager;
using Sustainalytics.LongRunningTaskManager.Interface;
using Sustainalytics.MongoDB.Extensions;
using Sustainalytics.RiskRatings.Reporting;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Globalization;
using System.Linq;
using System.Net.Http;

namespace Sustainalytics.RiskRatings.Tasks
{
    public class RiskRatingsReportDownloadTask : ILongRunningTask
    {
        public LongRunningTaskTypeEnum Type => LongRunningTaskTypeEnum.RiskRatingsReport;
        private RiskRatingsReportParameters parameters;

        public object Start(LongRunningTaskContext context)
        {
            return GetFileResult(context);
        }

        private ILongRunningTaskResult GetFileResult(LongRunningTaskContext context)
        {
            try
            {
                var clientDWConnectionString = GetConnectionString(ConnectionStringType.ClientDW);
                parameters = GetReportParameters(context.ParamJson, clientDWConnectionString);

                return TryGetReportFromS3(context, clientDWConnectionString);

            }
            catch (HttpRequestException httpRequestException)
            {
                LongRunningTaskManagerEventSource.Log.TaskFailed(LongRunningTaskTypeEnum.RiskRatingsReport, "", "", string.Format("Error {0}", httpRequestException));
                context.TaskStatus.AddError(new LongRunningTaskError
                {
                    ErrorCode = 7003,
                    Arguments = new List<string> { httpRequestException.Message }
                });
            }

            return null;
        }

        private static string GetConnectionString(ConnectionStringType connectionStringType)
        {
            var clientPlatformConnectionString = ConfigurationManager.ConnectionStrings["ClientPlatform"].ConnectionString;

            var connectionStringsManager = ConnectionStringsManager.GetInstance(ConnectionStringsRepository.GetInstance(clientPlatformConnectionString));

            return connectionStringsManager.GetConnectionString(connectionStringType);
        }


        private RiskRatingsReportParameters GetReportParameters(string paramJson, string connectionString)
        {
            parameters = JsonConvert.DeserializeObject<RiskRatingsReportParameters>(paramJson);

            var corporateDataCollection = MongoFactory.GetCollectionFromDatabase<CorporateData>(connectionString);
            var companyProfile = corporateDataCollection
                .Find(x => x.Id == parameters.CompanyId)
                .Project<CorporateData>(Builders<CorporateData>.Projection
                    .Include(cd => cd.CompanyName)
                    .Include(cd => cd.RiskRatingResearchState)
                    .Include(cd => cd.CoreRiskResearchState))
                .FirstOrDefault();

            if (companyProfile.ResearchParentId.HasValue)
            {
                parameters.CompanyId = companyProfile.ResearchParentId.Value;
                companyProfile = corporateDataCollection.Find(x => x.Id == parameters.CompanyId)
                .Project<CorporateData>(Builders<CorporateData>.Projection
                    .Include(cd => cd.CompanyName)
                    .Include(cd => cd.RiskRatingResearchState)
                    .Include(cd => cd.CoreRiskResearchState))
                .FirstOrDefault();
            }

            if (companyProfile == null)
                throw new HttpRequestException($"Failed to get company with Id {parameters.CompanyId}");

            if (companyProfile.CoreRiskResearchState.HasResearch && companyProfile.RiskRatingResearchState.HasResearch)
                throw new HttpRequestException($"The company with Id {parameters.CompanyId} has both core and comprehensive Risk Rating Research.");

            parameters.IsCore = companyProfile.CoreRiskResearchState.HasResearch;
            parameters.FileName = GetFileName(companyProfile);

            return parameters;
        }

        private string GetFileName(CorporateData company)
        {
            var reportName = parameters.IsSummaryReport 
                ? ReportName.RiskRatingsSummary 
                : ReportName.RiskRatings;

            if (parameters.IsCore) 
                reportName = parameters.IsSummaryReport 
                    ? ReportName.CoreRiskRatingsSummary 
                    : ReportName.CoreRiskRatings;

            return reportName.GetFullReportName(company.CompanyName, parameters.CompanyId);
        }

        private string GetReportType()
        {
            var reportType = parameters.IsSummaryReport
                    ? ReportType.SummaryRiskRatingsReport
                    : ReportType.RiskRatingsReport;

            if (parameters.IsCore)
                reportType = parameters.IsSummaryReport
                    ? ReportType.SummaryCoreRiskRatingsReport
                    : ReportType.CoreRiskRatingsReport;

            return reportType.ToString();
        }

        private static string GetDatabaseGroup(string connectionString)
        {
            var databaseGroup = DatabaseGroup.None;

            if (connectionString.Contains("_A"))
                databaseGroup = DatabaseGroup.A;
            if (connectionString.Contains("_B"))
                databaseGroup = DatabaseGroup.B;

            return databaseGroup.ToString();
        }

        private void GeneratePdf()
        {
            var connectionString = GetConnectionString(ConnectionStringType.RiskRatingsResearchDW);
            var databaseGroup = GetDatabaseGroup(connectionString);

            if (connectionString.Contains("RiskRatingsResearchDW_A"))
                connectionString = connectionString.Replace("RiskRatingsResearchDW_A", $"RiskRatingsResearchDW_{databaseGroup}");
            if (connectionString.Contains("RiskRatingsResearchDW_B"))
                connectionString = connectionString.Replace("RiskRatingsResearchDW_B", $"RiskRatingsResearchDW_{databaseGroup}");


            var connectionStrings = new Dictionary<string, string>
            {
                {"RiskRatingsResearchDW", connectionString}
            };

            var reportsManager = ReportsManager.GetInstance(100, connectionStrings);
          
            var isSuccessfullGeneration = reportsManager.GeneratePdfReport(parameters.CompanyId, parameters.IsSummaryReport, parameters.IsCore);
            if (!isSuccessfullGeneration)
                throw new HttpRequestException("The Risk rating report has not been generated.");
        }

        private LongRunningTaskS3FileResult TryGetReportFromS3(LongRunningTaskContext context, string connectionString)
        {
            var reportType = GetReportType();

            var remotePath = $"{reportType}_{GetDatabaseGroup(connectionString)}";

            var fileHandler = new S3FileHandler(remotePath, parameters.FileName);

            if (!fileHandler.FileExists())
            {
                try
                {
                    GeneratePdf();
                }
                catch
                {
                    context.Title = "Failed to get the Risk Ratings Report for specified company";
                    context.TaskStatus.AddError(new LongRunningTaskError
                    {
                        ErrorCode = 7001,
                        Arguments = new List<string> { "Failed to get the Risk Ratings Report for specified company" }
                    });

                    LongRunningTaskManagerEventSource.Log.TaskFailed(LongRunningTaskTypeEnum.RiskRatingsReport, "", "",
                        $"Failed to get the Risk Ratings Report for company ID={parameters.CompanyId}");

                    return null;
                }
            }

            var result = fileHandler.ReadFile();

            result.FileName = GetFileName();
            result.CompanyId = parameters.CompanyId;

            context.Title = result.FileName;
            context.TaskStatus.Progress = 100;

            return new LongRunningTaskS3FileResult
            {
                MimeType = "application/pdf",
                Bucket = result.S3Bucket,
                FileName = result.FileName,
                Key = result.S3Key
            };
        }


        private string GetFileName()
        {
            var ddmmyyyy = DateTime.UtcNow.ToString("ddMMyyyy", new CultureInfo("en-US"));
            var pos = parameters.FileName.Length - 40;

            // GUID + .pdf to be replaced with date
            var fileName = parameters.FileName.Remove(pos) + ddmmyyyy + ".pdf";

            return fileName;
        }

    }
}

